package com.startx.http.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Objects;
import java.util.Random;

import javax.inject.Inject;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.startx.http.entity.common.Sequence;
import com.startx.http.system.model.PageData;

@SuppressWarnings("unchecked")
public class MongodBaseDao<T> {
	
	@Inject
	private MongoTemplate mongoTemplate;
	/**
	 * ID随机地址
	 */
	private Random random = new Random();
	
	/**
	 * 获取泛型类
	 * @return
	 */
	private Class<?> getGenericClass() {
		Type sType = getClass().getGenericSuperclass();
		Type[] generics = ((ParameterizedType) sType).getActualTypeArguments();
		Class<T> mTClass = (Class<T>) (generics[0]);
		return mTClass;
	}
	/**
	 * 获取模板
	 * @return
	 */
	public MongoTemplate getMongoTemplate() {
		return mongoTemplate;
	}
	
	/**
	 * 统计数量
	 * @param query
	 * @return
	 */
	public long count(Query query) {
		return mongoTemplate.count(query, getGenericClass());
	}
	
	/**
	 * 统计数量
	 * @param query
	 * @return
	 */
	public long count(Query query,Class<?> clz) {
		return mongoTemplate.count(query, clz);
	}
	
	/**
	 * 根据ID获取数据
	 * @param id
	 * @return
	 */
	public T getById(Object id) {
		return (T) mongoTemplate.findOne(new Query(new Criteria("_id").is(id)), getGenericClass());
	}
	
	/**
	 * 根据ID获取数据
	 * @param id
	 * @return
	 */
	public <N extends Object>N getById(Object id,Class<?> clz) {
		return (N) mongoTemplate.findOne(new Query(new Criteria("_id").is(id)), clz);
	}
	
	/**
	 * 根据ID获取数据
	 */
	public void removeById(Object id) {
		mongoTemplate.remove(new Query(new Criteria("_id").is(id)), getGenericClass());
	}
	
	/**
	 * 根据ID获取数据
	 */
	public void removeById(Object id,Class<?> clz) {
		mongoTemplate.remove(new Query(new Criteria("_id").is(id)), clz);
	}
	
	/**
	 * 保存对象
	 */
	public void save(T t) {
		mongoTemplate.save(t);
	}
	
	/**
	 * 保存对象
	 */
	public void insert(T t) {
		mongoTemplate.insert(t);
	}
	
	/**
	 * 保存一组对象
	 */
	public void insertAll(List<T> ts) {
		mongoTemplate.insertAll(ts);
	}
	
	/**
	 * 保存对象
	 */
	public void saveObject(Object t) {
		mongoTemplate.save(t);
	}
	
	/**
	 * 保存对象
	 */
	public void insertObject(Object t) {
		mongoTemplate.insert(t);
	}
	
	/**
	 * 保存一组对象
	 */
	public void insertAllObject(List<?> ts) {
		mongoTemplate.insertAll(ts);
	}
	
	/**
	 * 检索
	 * @param query
	 */
	public List<T> list(Query query) {
		return (List<T>) mongoTemplate.find(query,getGenericClass());
	}

	/**
	 * 检索
	 * @param query
	 */
	public List<T> list(Query query,Pageable pageable) {
		if(!Objects.isNull(pageable)) {
			query.with(pageable);
		}
		return (List<T>) mongoTemplate.find(query,getGenericClass());
	}
	
	/**
	 * 检索
	 * @param query
	 */
	public List<T> list(Query query,Sort sort) {
		if(!Objects.isNull(sort)) {
			query.with(sort);
		}
		return (List<T>) mongoTemplate.find(query,getGenericClass());
	}
	
	/**
	 * 检索
	 * @param query
	 */
	public <N extends Object>List<N> listObject(Query query,Class<?> clz) {
		return (List<N>) mongoTemplate.find(query,clz);
	}
	
	/**
	 * 检索
	 * @param query
	 */
	public <N extends Object>List<N> listObject(Query query,Sort sort,Class<?> clz) {
		if(!Objects.isNull(sort)) {
			query.with(sort);
		}
		return (List<N>) mongoTemplate.find(query,clz);
	}
	
	/**
	 * 检索
	 * @param query
	 */
	public <N extends Object>List<N> listObject(Query query,Pageable pageable,Class<?> clz) {
		if(!Objects.isNull(pageable)) {
			query.with(pageable);
		}
		return (List<N>) mongoTemplate.find(query,clz);
	}

	/**
	 * 检索
	 * @param query
	 */
	public PageData<T> find(Query query) {
		return findObject(query, null);
	}
	
	/**
	 * 检索
	 * @param query
	 */
	public PageData<T> find(Query query,Pageable pageable) {
		PageData<T> page = PageData.build();
		long count = mongoTemplate.count(query, getGenericClass());
		page.setTotalRecord(count);
		
		if(!Objects.isNull(pageable)) {
			query.with(pageable);
		}
		
		List<T> datas = (List<T>) mongoTemplate.find(query,getGenericClass());
		page.setList(datas);
		page.setPageSize(pageable.getPageSize());
		page.setTotalPage((int)(page.getTotalRecord()+page.getPageSize()-1)/page.getPageSize());
		
		return page;
	}
	
	/**
	 * 检索
	 * @param query
	 */
	public <N extends Object>PageData<N> findObject(Query query,Class<?> clz) {
		return findObject(query, null, clz);
	}
	
	/**
	 * 检索
	 * @param query
	 */
	public <N extends Object>PageData<N> findObject(Query query,Pageable pageable,Class<?> clz) {
		PageData<N> page = PageData.build();
		long count = mongoTemplate.count(query, clz);
		page.setTotalRecord(count);
		
		if(!Objects.isNull(pageable)) {
			query.with(pageable);
		}
		
		List<N> datas = (List<N>) mongoTemplate.find(query,clz);
		page.setList(datas);
		page.setPageSize(pageable.getPageSize());
		page.setTotalPage((int)(page.getTotalRecord()+page.getPageSize()-1)/page.getPageSize());
		
		return page;
	}
	
	/**
	 * 获取下一个ID
	 * @return
	 */
	public long getNextSequenceId(int step) {
		return getNextSequenceId(getGenericClass(),step);
	}
	
	/**
	 * 获取下一个ID
	 * @return
	 */
	public long getNextSequenceId(Class<?> clz, int step) {
		Query query = new Query(Criteria.where("collName").is(clz.getSimpleName()));
		Update update = new Update();
		
		
		if(step == -1) {
			update.inc("sequenceId", random.nextInt(200)+1);
		} else {
			update.inc("sequenceId", step);
		}
		
		FindAndModifyOptions options = new FindAndModifyOptions();
		options.upsert(true);
		options.returnNew(true);
		Sequence seq = mongoTemplate.findAndModify(query, update, options, Sequence.class);
		return seq.getSequenceId();
	}
}
